#include <cassert>
#include <stdexcept>
#include "PhysicObject.hpp"
#include "PhysicWorld.hpp"


PhysicObject::PhysicObject():
m_body(NULL)
{
}

PhysicObject::~PhysicObject()
{
   if(m_body)
   {
        GET_PHYSIC_WORLD->DestroyBody(m_body);
        m_body = NULL;
   }
}

void PhysicObject::load(json::Object &data)
{
    assert(GET_PHYSIC_WORLD != NULL);
    if(m_body)
    {
        GET_PHYSIC_WORLD->DestroyBody(m_body);
        m_body = NULL;
    }
    json::String &dtype = data["type"]; 
    json::Number &dangle = data["angle"];
    json::Number &dposx = data["position"]["x"];
    json::Number &dposy = data["position"]["y"];
    json::Boolean &dfixedRotation = data["fixedRotation"];
    json::Boolean &dbullet = data["bullet"];
    
    b2BodyDef bodyDef;
    if(dtype.Value() == "static")
        bodyDef.type = b2_staticBody;
    else if(dtype.Value() == "dynamic")
        bodyDef.type = b2_dynamicBody;
    else if(dtype.Value() == "kinematic")
        bodyDef.type = b2_kinematicBody;
    else
        throw std::runtime_error("Invalid data for body type.");
    
    bodyDef.angle = dangle.Value();
    bodyDef.position = b2Vec2(dposx.Value(),dposy.Value());
    bodyDef.fixedRotation = dfixedRotation.Value();
    bodyDef.bullet = dbullet.Value();
    bodyDef.userData = NULL;
    
    m_body = GET_PHYSIC_WORLD->CreateBody(&bodyDef);

    json::Array &fixtures = data["fixtures"];
    for(unsigned int i = 0; i < fixtures.Size(); ++i)
    {
        json::String& dshapeType = fixtures[i]["shapeType"];
        json::Number& dfriction = fixtures[i]["friction"];
        json::Number& drestitution = fixtures[i]["restitution"];
        json::Number& ddensity = fixtures[i]["density"];
        json::Boolean& dsensor = fixtures[i]["sensor"];
        
        b2FixtureDef fixDef;
        
        if(dshapeType.Value() == "rectangle")
        {
            json::Number& dwidth = fixtures[i]["width"];
            json::Number& dheight = fixtures[i]["height"];
            b2PolygonShape *shape = new b2PolygonShape();
            shape->SetAsBox(dwidth.Value()/(2*SFML_TO_BOX2D),dheight.Value()/(2*SFML_TO_BOX2D));
            fixDef.shape = shape;
        }
        else if(dshapeType.Value() == "square")
        {
            json::Number& dside = fixtures[i]["side"];
            b2PolygonShape *shape = new b2PolygonShape();
            shape->SetAsBox(dside.Value()/(2*SFML_TO_BOX2D),dside.Value()/(2*SFML_TO_BOX2D));
            fixDef.shape = shape;      
        }
        
        else if(dshapeType.Value() == "circle")
        {
            json::Number& dradius = fixtures[i]["radius"];
            b2CircleShape *shape = new b2CircleShape();
            shape->m_radius = dradius.Value() * SFML_TO_BOX2D;   
            fixDef.shape = shape;
        }
        else
            throw std::runtime_error("Invalid shape type.");
        
        fixDef.friction = dfriction.Value();
        fixDef.restitution = drestitution.Value();
        fixDef.density = ddensity.Value();
        fixDef.isSensor = dsensor.Value();
        fixDef.userData = NULL;
        m_body->CreateFixture(&fixDef);
    }
}

sf::Vector2f PhysicObject::convertPosToSFML()
{
    assert(m_body != NULL);
    
    sf::Vector2f pos;
    pos.x = m_body->GetPosition().x * BOX2D_TO_SFML;
    pos.y = - m_body->GetPosition().y * BOX2D_TO_SFML;
    
    return pos;
}
